/*
 * edulisp_lextable.cpp
 *
 *  Created on: 13.04.2011
 *      Author: Lufterd
 */

#include "edulisp_nametable.hpp"

NameTable_Entry::NameTable_Entry(string* pText_, LexemeType eLexemeType, int Value)
	: eLexemeType_(eLexemeType), eDataType(DT_INT),
	  pText((pText_) ? new string(*pText_) : NULL), Owner(-1)
{
    Value_ = new int(Value);
}

NameTable_Entry::NameTable_Entry(LexemeType eLexemeType, string& Value)
	: eLexemeType_(eLexemeType), eDataType(DT_STRING), pText(NULL), Owner(-1)
{
    Value_ = new string(Value);
}

NameTable_Entry::NameTable_Entry(string* pText_, LexemeType eLexemeType,
		double Value)
	: eLexemeType_(eLexemeType), eDataType(DT_DOUBLE),
	  pText((pText_) ? new string(*pText_) : NULL), Owner(-1)
{
    Value_ = new double(Value);
}

NameTable_Entry::NameTable_Entry(string* pText_, int Owner_)
	: eLexemeType_(LT_ID), eDataType(DT_NULL),
	  pText((pText_) ? new string(*pText_) : NULL), Owner(Owner_) {}

NameTable_Entry::NameTable_Entry(string* pText_, LexemeType eLexemeType)
	: eLexemeType_(eLexemeType), eDataType(DT_NULL),
	  pText((pText_) ? new string(*pText_) : NULL), Owner(-1) {}

void NameTable_Entry::DeleteData()
{
	switch(eDataType)
	{
	case DT_INT:
		delete reinterpret_cast<int *>(Value_);
		break;
	case DT_STRING:
		delete reinterpret_cast<string *>(Value_);
		break;
	case DT_DOUBLE:
		delete reinterpret_cast<double *>(Value_);
		break;
	case DT_NULL:
		return;
	case DT_USERFUNCTION:
		delete reinterpret_cast<FunctionDescriptor *>(Value_);
	}
	eDataType = DT_NULL;
}

NameTable_Entry::~NameTable_Entry()
{
	DeleteData();

	delete pText;
}

void NameTable_Entry::CopyData(const NameTable_Entry& other, bool NewEntry)
{
	if (eDataType != other.eDataType)
	{
		if (!NewEntry)
			DeleteData();
		switch(other.eDataType)
		{
		case DT_INT:
			Value_ = new int(*(reinterpret_cast<int *>(other.Value_)));
			break;
		case DT_STRING:
			Value_ = new string(*(reinterpret_cast<string *>(other.Value_)));
			break;
		case DT_DOUBLE:
			Value_ = new double(*(reinterpret_cast<double *>(other.Value_)));
		case DT_NULL:
			break;
		case DT_USERFUNCTION:
			Value_ = new FunctionDescriptor(
					*(reinterpret_cast<FunctionDescriptor *>(other.Value_)));
		}
		eDataType = other.eDataType;
	}
	else
	{
		switch(other.eDataType)
		{
		case DT_INT:
			*(reinterpret_cast<int *>(Value_)) =
					*(reinterpret_cast<int *>(other.Value_));
			break;
		case DT_STRING:
			*(reinterpret_cast<string *>(Value_)) =
					*(reinterpret_cast<string *>(other.Value_));
			break;
		case DT_DOUBLE:
			*(reinterpret_cast<double *>(Value_)) =
					*(reinterpret_cast<double *>(other.Value_));
		case DT_NULL:
			break;
		case DT_USERFUNCTION:
			*(reinterpret_cast<FunctionDescriptor *>(Value_)) =
					*(reinterpret_cast<FunctionDescriptor *>(other.Value_));
		}
	}
}

NameTable_Entry::NameTable_Entry(const NameTable_Entry& other)
	: eLexemeType_(other.eLexemeType_), eDataType(DT_NULL),
	  pText((other.pText) ? new string(*(other.pText)) : NULL),
	  Owner(other.Owner)
{
	CopyData(other, true);
}

string *NameTable_Entry::GetString()
{
	return (eDataType == DT_STRING) ? reinterpret_cast<string *>(Value_) : NULL;
}

int *NameTable_Entry::GetInteger()
{
	return (eDataType == DT_INT) ? reinterpret_cast<int *>(Value_) : NULL;
}

double *NameTable_Entry::GetFloat()
{
	return (eDataType == DT_DOUBLE) ? reinterpret_cast<double *>(Value_) : NULL;
}

FunctionDescriptor* NameTable_Entry::GetFunctionDescriptor()
{
	return (eDataType == DT_USERFUNCTION) ?
			reinterpret_cast<FunctionDescriptor *>(Value_) : NULL;
}

DataType NameTable_Entry::GetDataType()
{
	return eDataType;
}

LexemeType NameTable_Entry::GetLexemeType()
{
	return eLexemeType_;
}

string* NameTable_Entry::GetText()
{
	return pText;
}

//Получить индекс элемента по имени и владельцу
int NameTable::NameIndex(string& Name, int Owner_)
{
	string *str;
	int Owner;
	int RootIndex = -1;
	for(unsigned int i = 0; i < size(); i++)
	{
		str = at(i)->GetText();
		Owner = at(i)->GetOwner();
		if (str && (*(str) == Name))
		{
			if (Owner == Owner_)
				return i;
			if (Owner == -1)
				RootIndex = i;
		}
	}

	//Если не было найдено записи с нужным владельцем, то возвращаем
	//запись без владельца, если такая была найдена
	return RootIndex;
}

//Получить индекс элемента по строковому значению
int NameTable::StringValueIndex(string& StringValue)
{
	for(unsigned int i = 0; i < size(); i++)
	{
		NameTable_Entry& Entry = *at(i);
		if ((Entry.GetDataType() == DT_STRING) &&
				(*(Entry.GetString()) == StringValue))
			return i;
	}

	return -1;
}

//Перегрузка оператора потокового вывода
ostream& operator<<(ostream& stream, NameTable_Entry& obj)
{
	switch(obj.GetDataType())
	{
	case DT_STRING:
		stream << *(obj.GetString());
		break;
	case DT_INT:
		stream << *(obj.GetInteger());
		break;
	case DT_DOUBLE:
		stream << *(obj.GetFloat());
		break;
	case DT_NULL:
		stream << "NULL";
		break;
	case DT_USERFUNCTION:
		stream << "FUNCTION";
		break;
	default:
		stream << "UNKNOWN";
	}

	return stream;
}

void NameTable_Entry::SetLexemeType(LexemeType LexemeType_)
{
	eLexemeType_ = LexemeType_;
}

//Универсальная проверка на равенство данных в объекте нулю
bool NameTable_Entry::ZeroValue()
{
	switch(GetDataType())
	{
	case DT_STRING:
		return ((GetString())->empty());
	case DT_INT:
		return (!(*(GetInteger())));
	case DT_DOUBLE:
		return (!(*(GetFloat())));
	case DT_NULL:
		return true;
	case DT_USERFUNCTION: default:
		return false;
	}
}

//Перегрузка оператора сравнения
bool NameTable_Entry::operator==(NameTable_Entry& obj)
{
	switch(GetDataType())
	{
	case DT_DOUBLE:
		switch(obj.GetDataType())
		{
		case DT_DOUBLE:
			return (*(GetFloat()) == *(obj.GetFloat()));
		case DT_INT:
			return (*(GetFloat()) == *(obj.GetInteger()));
		default:
			return false;
		}
		break;
	case DT_INT:
		switch(obj.GetDataType())
		{
		case DT_DOUBLE:
			return (*(GetInteger()) == *(obj.GetFloat()));
		case DT_INT:
			return (*(GetInteger()) == *(obj.GetInteger()));
		default:
			return false;
		}
		break;
	case DT_STRING:
		switch(obj.GetDataType())
		{
		case DT_STRING:
			return (*(GetString()) == *(obj.GetString()));
		default:
			return false;
		}
		break;
	case DT_NULL:
		return false;
	default:
		return false;
	}
	return true;
}

//Перегрузка оператора потокового ввода
istream& operator>>(istream& stream, NameTable_Entry& obj)
{
	string buf;
	istringstream is;

	stream >> buf;

	int val1;
	is.str(buf);
	is >> val1;
	if (is.fail())
	{
		double val2;
		is.str(buf);
		is >> val2;
		if (is.fail())
		{
			string val3;

			is.str(buf);
			is >> val3;

			obj.SetData(val3);
		}
		else
			obj.SetData(val2);
	}
	else
		obj.SetData(val1);

	return stream;
}

void NameTable_Entry::SetData(int Value)
{
	if (eDataType != DT_INT)
	{
		DeleteData();
		Value_ = new int(Value);
		eDataType = DT_INT;
	}
	else
		*(reinterpret_cast<int *>(Value_)) = Value;
}

void NameTable_Entry::SetData(string& Value)
{
	if (eDataType != DT_STRING)
	{
		DeleteData();
		Value_ = new string(Value);
		eDataType = DT_STRING;
	}
	else
		*(reinterpret_cast<string *>(Value_)) = Value;
}

void NameTable_Entry::SetData(double Value)
{
	if (eDataType != DT_INT)
	{
		DeleteData();
		Value_ = new double(Value);
		eDataType = DT_DOUBLE;
	}
	else
		*(reinterpret_cast<double *>(Value_)) = Value;
}

int NameTable_Entry::GetOwner()
{
	return Owner;
}

/*int OwnerIndex(NameTable& vNameTable, NameTable_Entry& Entry)
{
	NameTable::iterator i3 = (Entry.GetOwner()) ? *Entry.GetOwner()
			: vNameTable.end();
	if (!(Entry.GetOwner()))
		return -1;
	unsigned int i2 = 0;
	for(NameTable::iterator i = vNameTable.begin();
			i != vNameTable.end(); i++, i2++)
		if (i == *(Entry.GetOwner()))
			return i2;

	return -1;
}*/

//Создание дескриптора функции в качестве данных объекта
FunctionDescriptor* NameTable_Entry::CreateFunctionDescriptor()
{
	DeleteData();
	eDataType = DT_USERFUNCTION;
	FunctionDescriptor *Descriptor = new FunctionDescriptor();
	Value_ = Descriptor;

	return Descriptor;
}

FunctionDescriptor::FunctionDescriptor(Lexeme FunctionID)
	: pArguments(NULL), FunctionID_(FunctionID) { }

FunctionDescriptor::FunctionDescriptor(const FunctionDescriptor& obj)
	//: pArguments((obj.pArguments) ? new ArgumentList(*(obj.pArguments)) : NULL),
	: pArguments((obj.pArguments) ? new ArgumentDescriptor(*(obj.pArguments)) : NULL),
			Lexemes(obj.Lexemes) { }

FunctionDescriptor::~FunctionDescriptor()
{
	delete pArguments;
}

//ArgumentList* FunctionDescriptor::CreateArgumentList()
ArgumentDescriptor* FunctionDescriptor::CreateArgumentList()
{
	//return (pArguments = new ArgumentList());
	return (pArguments = new ArgumentDescriptor());
}

//ArgumentList* FunctionDescriptor::GetArgumentList()
ArgumentDescriptor* FunctionDescriptor::GetArgumentList()
{
	return pArguments;
}

LexemeList& FunctionDescriptor::GetLexemeList()
{
	return Lexemes;
}

Lexeme FunctionDescriptor::GetFunctionID()
{
	return FunctionID_;
}

void FunctionDescriptor::SetFunctionID(Lexeme FunctionID)
{
	FunctionID_ = FunctionID;
}

//Проверяет, является ли переменная локальной относительно описываемой функции,
//и добавляет её в шаблонную карту имён
void FunctionDescriptor::CheckAndAddLocalVariable(Lexeme LocalVariable_,
		NameTable& NameTable_)
{
	if ((NameTable_[LocalVariable_]->GetOwner() == FunctionID_)
			&& (LocalVariables_.find(LocalVariable_) == LocalVariables_.end()))
		LocalVariables_.insert(LocalVariable(LocalVariable_,
				new NameTable_Entry(*NameTable_[LocalVariable_])));
}

LocalVariables& FunctionDescriptor::GetLocalVariables()
{
	return LocalVariables_;
}

NameTable::~NameTable()
{
	for(NameTable::iterator i = begin();
				i != end(); i++)
			delete *i;
}

LocalVariables::~LocalVariables()
{
	for(LocalVariables::iterator i = begin();
				i != end(); i++)
			delete i->second;
}
